use crate::mqi;
use std::ffi::{CString};
use std::os::raw::{c_char};
use failure::Error;
use crate::{strcpy, set_mqmd_default};

pub struct MQMessage {
    msg_descriptor: mqi::MQMD,
    data: CString,
}

impl From<&str> for MQMessage {
    fn from(s: &str) -> MQMessage {
        let data = match CString::new(s){
            Ok(cs) => cs,
            Err(e) => panic!("{:?}\nCan not create CString from {:?}", s, e),
        };
        MQMessage {
            msg_descriptor: MQMsgDescBuilder::default().build(),
            data,
        }
    } 
}

impl From<String> for MQMessage {
    fn from(s: String) -> MQMessage {
        let sref: &str = s.as_ref();
        let data = match CString::new(sref){
            Ok(cs) => cs,
            Err(e) => panic!("{:?}\nCan not create CString from {:?}", s, e),
        };
        MQMessage {
            msg_descriptor: MQMsgDescBuilder::default().build(),
            data,
        }
    } 
}

impl MQMessage {
    pub fn data_as_ptr(&self) -> *const c_char {
        self.data.as_ptr()
    }
    pub fn data_as_bytes(&self) -> &[u8] {
        self.data.as_bytes()
    }
    pub fn as_string(&self) -> Result<String, Error> {
        Ok(std::str::from_utf8(&self.data.as_bytes())?.to_owned())
    }
    pub fn as_str(&self) -> Result<&str, Error> {
        Ok(std::str::from_utf8(&self.data.as_bytes())?)
    }
    pub fn msg_descriptor(&self) -> mqi::MQMD {
        self.msg_descriptor
    }
} 

#[derive(Clone)]
pub struct MQMsgDescBuilder {
    mqmd: mqi::MQMD,
}

impl MQMsgDescBuilder {
    pub fn new() -> MQMsgDescBuilder{
        let mut mqmd: mqi::MQMD = unsafe { std::mem::zeroed() };
        unsafe {
            set_mqmd_default(&mut mqmd)
        };
        MQMsgDescBuilder{ mqmd }
    }
    pub fn build(&self) -> mqi::MQMD {
        self.mqmd
    }
    fn version(&mut self, mqmd_ver: i32) -> &mut Self {
        self.mqmd.Version = mqmd_ver;
        self
    }
    fn expiry(&mut self, mqei: i32) -> &mut Self {
        self.mqmd.Expiry = mqei;
        self
    }
    fn msg_type(&mut self, mqmt: i32) -> &mut Self {
        self.mqmd.MsgType = mqmt;
        self
    }
    fn priority(&mut self, pri: i32) -> &mut Self {
        self.mqmd.Priority = pri;
        self
    }
    fn persistence(&mut self, mqper: i32) -> &mut Self {
        self.mqmd.Persistence = mqper;
        self
    }
    fn encoding(&mut self, mqenc: i32) -> &mut Self {
        self.mqmd.Encoding = mqenc;
        self
    }
    fn coded_charset_id(&mut self, mqccsi: i32) -> &mut Self {
        self.mqmd.CodedCharSetId = mqccsi;
        self
    }
    fn report(&mut self, mqro: i32) -> &mut Self {
        self.mqmd.Report = mqro;
        self
    }
    fn feedback(&mut self, mqfb: i32) -> &mut Self {
        self.mqmd.Feedback = mqfb;
        self
    }
    fn format(&mut self, mqfmt: &[u8; 9]) -> &mut Self {
        let mut format: [i8; 8] = [0;8];
        strcpy(mqfmt, &mut format, 8);
        self.mqmd.Format = format;
        self
    }
    fn reply_to_queue(&mut self, name: &str) -> &mut Self {
        let mut result: [i8;48] = [0;48];
        strcpy(name.as_bytes(), &mut result, name.len());
        self.mqmd.ReplyToQ = result;
        self
    }
}

impl Default for MQMsgDescBuilder {
    fn default() -> MQMsgDescBuilder {
        MQMsgDescBuilder::new()
            .version(mqi::MQMD_VERSION_1) 
            .report(mqi::MQRO_NONE)
            .msg_type(mqi::MQMT_DATAGRAM)
            .expiry(mqi::MQEI_UNLIMITED)
            .feedback(mqi::MQFB_NONE)
            .priority(1)
            .encoding(mqi::MQENC_NATIVE)
            .coded_charset_id(mqi::MQCCSI_Q_MGR)
            .persistence(mqi::MQPER_PERSISTENT)
            .format(mqi::MQFMT_STRING)
            .reply_to_queue("").clone()
    }
}

